import subprocess
import re
import time
import threading
from datetime import datetime
from backend.database import db
from backend.models.device import Device
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('device_manager')

# 延迟导入，避免循环导入
def get_app():
    """获取Flask应用实例，使用延迟导入避免循环依赖"""
    import sys
    if 'app' not in sys.modules:
        from app import app
    return sys.modules['app'].app

class DeviceManager:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(DeviceManager, cls).__new__(cls)
                cls._instance.devices = {}
                cls._instance.device_pool = []
                cls._instance.running = False
                cls._instance.monitor_thread = None
        return cls._instance
    
    def start_monitor(self):
        """启动设备监控线程"""
        if not self.running:
            self.running = True
            self.monitor_thread = threading.Thread(target=self._monitor_devices, daemon=True)
            self.monitor_thread.start()
            logger.info("设备监控已启动")
    
    def stop_monitor(self):
        """停止设备监控线程"""
        if self.running:
            self.running = False
            if self.monitor_thread:
                self.monitor_thread.join(timeout=3)
            logger.info("设备监控已停止")
    
    def _monitor_devices(self):
        """监控设备连接状态"""
        while self.running:
            self.scan_devices()
            self.update_device_status()
            time.sleep(10)  # 每10秒扫描一次
    
    def scan_devices(self):
        """扫描连接的设备"""
        try:
            # 使用adb命令列出设备
            result = subprocess.run(['adb', 'devices', '-l'], capture_output=True, text=True)
            if result.returncode != 0:
                logger.error(f"adb命令执行失败: {result.stderr}")
                return
            
            # 解析设备列表
            device_lines = result.stdout.strip().split('\n')[1:]  # 跳过标题行
            current_devices = set()
            
            for line in device_lines:
                if line.strip() and 'device' in line:
                    parts = line.strip().split()
                    device_id = parts[0]
                    current_devices.add(device_id)
                    
                    # 如果设备不存在于devices字典中，添加它
                    if device_id not in self.devices:
                        device_info = self._get_device_info(device_id)
                        self.devices[device_id] = device_info
                        # 注册到数据库
                        self._register_device(device_info)
                        logger.info(f"发现新设备: {device_id} - {device_info['model']}")
            
            # 检查离线设备
            for device_id in list(self.devices.keys()):
                if device_id not in current_devices:
                    self._mark_device_offline(device_id)
                    logger.info(f"设备离线: {device_id}")
        except Exception as e:
            logger.error(f"扫描设备时发生错误: {str(e)}")
    
    def _get_device_info(self, device_id):
        """获取设备详细信息"""
        info = {
            'device_id': device_id,
            'model': 'Unknown',
            'brand': 'Unknown',
            'os_version': 'Unknown',
            'battery_level': 0
        }
        
        # 获取设备型号和品牌
        try:
            result = subprocess.run(['adb', '-s', device_id, 'shell', 'getprop', 'ro.product.model'], capture_output=True, text=True)
            if result.returncode == 0:
                info['model'] = result.stdout.strip()
            
            result = subprocess.run(['adb', '-s', device_id, 'shell', 'getprop', 'ro.product.brand'], capture_output=True, text=True)
            if result.returncode == 0:
                info['brand'] = result.stdout.strip()
            
            # 获取Android版本
            result = subprocess.run(['adb', '-s', device_id, 'shell', 'getprop', 'ro.build.version.release'], capture_output=True, text=True)
            if result.returncode == 0:
                info['os_version'] = result.stdout.strip()
            
            # 获取电池电量
            result = subprocess.run(['adb', '-s', device_id, 'shell', 'dumpsys', 'battery'], capture_output=True, text=True)
            if result.returncode == 0:
                battery_match = re.search(r'level: (\d+)', result.stdout)
                if battery_match:
                    info['battery_level'] = int(battery_match.group(1))
        except Exception as e:
            logger.error(f"获取设备信息时发生错误: {str(e)}")
        
        return info
    
    def _register_device(self, device_info):
        """注册设备到数据库"""
        try:
            app = get_app()
            with app.app_context():
                # 检查设备是否已存在
                existing_device = Device.query.filter_by(device_id=device_info['device_id']).first()
                if existing_device:
                    # 更新现有设备信息
                    existing_device.device_name = f"{device_info['brand']} {device_info['model']}"
                    existing_device.model = device_info['model']
                    existing_device.brand = device_info['brand']
                    existing_device.os_version = device_info['os_version']
                    existing_device.status = '在线'
                    existing_device.battery_level = device_info['battery_level']
                else:
                    # 创建新设备记录
                    new_device = Device(
                        device_id=device_info['device_id'],
                        device_name=f"{device_info['brand']} {device_info['model']}",
                        model=device_info['model'],
                        brand=device_info['brand'],
                        os_version=device_info['os_version'],
                        status='在线',
                        battery_level=device_info['battery_level']
                    )
                    db.session.add(new_device)
                db.session.commit()
        except Exception as e:
            if 'db' in locals():
                db.session.rollback()
            logger.error(f"注册设备到数据库时发生错误: {str(e)}")
    
    def _mark_device_offline(self, device_id):
        """标记设备为离线"""
        try:
            app = get_app()
            with app.app_context():
                device = Device.query.filter_by(device_id=device_id).first()
                if device:
                    device.status = '离线'
                    device.current_task_id = None
                    db.session.commit()
                
            if device_id in self.devices:
                del self.devices[device_id]
        except Exception as e:
            if 'db' in locals():
                db.session.rollback()
            logger.error(f"标记设备离线时发生错误: {str(e)}")
    
    def update_device_status(self):
        """更新所有设备的状态"""
        try:
            app = get_app()
            with app.app_context():
                devices = Device.query.all()
                for device in devices:
                    if device.device_id in self.devices:
                        device_info = self._get_device_info(device.device_id)
                        device.battery_level = device_info['battery_level']
                        device.status = '在线'
                    else:
                        device.status = '离线'
                        device.current_task_id = None
                db.session.commit()
        except Exception as e:
            if 'db' in locals():
                db.session.rollback()
            logger.error(f"更新设备状态时发生错误: {str(e)}")
    
    def get_available_devices(self):
        """获取所有可用设备"""
        try:
            app = get_app()
            with app.app_context():
                return Device.query.filter_by(status='在线').filter_by(current_task_id=None).all()
        except Exception as e:
            logger.error(f"获取可用设备时发生错误: {str(e)}")
            return []
    
    def allocate_device(self):
        """分配一个可用设备"""
        try:
            app = get_app()
            with app.app_context():
                device = Device.query.filter_by(status='在线').filter_by(current_task_id=None).first()
                if device:
                    device.status = '忙碌'
                    db.session.commit()
                    logger.info(f"设备已分配: {device.device_id}")
                return device
        except Exception as e:
            if 'db' in locals():
                db.session.rollback()
            logger.error(f"分配设备时发生错误: {str(e)}")
            return None
    
    def release_device(self, device_id):
        """释放设备"""
        try:
            app = get_app()
            with app.app_context():
                device = Device.query.filter_by(device_id=device_id).first()
                if device:
                    device.status = '在线'
                    device.current_task_id = None
                    db.session.commit()
                    logger.info(f"设备已释放: {device_id}")
                return True
        except Exception as e:
            if 'db' in locals():
                db.session.rollback()
            logger.error(f"释放设备时发生错误: {str(e)}")
            return False
    
    def execute_command(self, device_id, command):
        """在指定设备上执行命令"""
        try:
            result = subprocess.run(['adb', '-s', device_id, 'shell', command], capture_output=True, text=True)
            return {
                'success': result.returncode == 0,
                'stdout': result.stdout,
                'stderr': result.stderr
            }
        except Exception as e:
            logger.error(f"执行命令时发生错误: {str(e)}")
            return {
                'success': False,
                'stderr': str(e)
            }
    
    def get_device_by_id(self, device_id):
        """通过ID获取设备"""
        try:
            return Device.query.filter_by(device_id=device_id).first()
        except Exception as e:
            logger.error(f"获取设备时发生错误: {str(e)}")
            return None